/**
 *
 */
package com.yuexunit.finance.common.util;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtNewConstructor;
import javassist.CtNewMethod;
import javassist.LoaderClassPath;

/**
 * 通用排序帮助类
 *
 */
class OrderUtils {
    /**
     * 排序对象
     */
    private static Map<String, Comparator> comparators = new ConcurrentHashMap<String, Comparator>();

    private static final Pattern IMPORT_PATTERN = Pattern.compile("import\\s+([\\w\\.\\*]+);\n");

    private static final Pattern IMPLEMENTS_PATTERN = Pattern.compile("\\s+implements\\s+([\\w\\.]+)\\s*\\{\n");

    private static final Pattern METHODS_PATTERN = Pattern.compile("\n(private|public|protected)\\s+");

    private static final Pattern FIELD_PATTERN = Pattern.compile("[^\n]+=[^\n]+;");

    public static String createCopmare(Class<?> t, String filedCol, boolean desc) throws Exception {
        StringBuilder codeBuidler = new StringBuilder();


        codeBuidler.append("package " + t.getPackage().getName() + ";");
        codeBuidler.append("\nimport com.howbuy.common.compare.PinyinComparator;");
        codeBuidler.append("\npublic class  " + t.getSimpleName() + "$" + filedCol + " implements " + "java.util.Comparator {");
        String className = t.getName();
        codeBuidler.append("\n int result = 0;");
        codeBuidler.append("\npublic int compare(Object param1,Object param2) {");
        codeBuidler.append("\n" + className + " info1 = (" + className + ")param1;");
        codeBuidler.append("\n" + className + " info2 = (" + className + ")param2;");
        String getFiledStr = filedCol.substring(0, 1).toUpperCase() + filedCol.substring(1);
        Field filed = t.getDeclaredField(filedCol);
        String filedType = filed.getType().getName();
        if (filedType != null && filedType.length() <= 8) {
            codeBuidler.append("\n" + filedType + " value1 = info1.get" + getFiledStr + "();");
            codeBuidler.append("\n" + filedType + " value2 = info2.get" + getFiledStr + "();");
            codeBuidler.append("\n if (value1 > value2) result = 1;else if (value1 < value2) result = -1;");
        } else {


            codeBuidler.append("\nComparable value1 = info1.get" + getFiledStr + "();");
            codeBuidler.append("\nComparable value2 = info2.get" + getFiledStr + "();");
            codeBuidler.append("\nif (null == value1 && value2 == null) result = 0;else if (null == value2) return -1; else if (null == value1) return 1;");
            codeBuidler.append("\nelse if (value1 instanceof java.lang.String) {java.util.Comparator pinyinComparator = new PinyinComparator();result = pinyinComparator.compare((String)value1, (String)value2);}");
            codeBuidler.append("\nelse {result = value1.compareTo(value2);}");
        }
        codeBuidler.append("\nif (" + desc + ") result = 0 - result;");
        codeBuidler.append("return result;}");
        codeBuidler.append("}");

        return codeBuidler.toString();
    }

    /**
     * 创建排序的类的代码，根据多个排序字段
     *
     * @param orderClazz 待排序对象
     * @param orders
     * @return String
     * @throws Exception
     */
    public static String createCopmare(final Class orderClazz, OrderField... orders) throws Exception {
        StringBuilder codeBuidler = new StringBuilder();
        codeBuidler.append("package " + orderClazz.getPackage().getName() + ";");
        codeBuidler.append("\nimport com.howbuy.common.compare.PinyinComparator;");
        codeBuidler.append("\npublic class ").append(getNewClassName(orderClazz, orders)).append(" implements java.util.Comparator {");
        String className = orderClazz.getName();
        codeBuidler.append("\npublic int compare(Object param1,Object param2) {");
        codeBuidler.append("\n" + className + " info1 = (" + className + ")param1;");
        codeBuidler.append("\n" + className + " info2 = (" + className + ")param2;");
        for (int i = 0, len = orders.length; i < len; i++) {
            Class tempOrderClazz =  orderClazz;
            codeBuidler.append("\n int result = 0;");
            OrderField orderField = orders[i];
            String getFiledStr = orderField.getFiled().substring(0, 1).toUpperCase() + orderField.getFiled().substring(1);
            Field filed = null;
            for (;!tempOrderClazz.equals(Object.class); tempOrderClazz = tempOrderClazz
                    .getSuperclass()) { 
            	try {
            	filed = tempOrderClazz.getDeclaredField(orderField.getFiled());
            	break;
            	}  catch (java.lang.NoSuchFieldException e) {
					
				}
            }
            if (null == filed) {
            	throw new IllegalArgumentException(getFiledStr +" = NoSuchFieldException ");
            }
            String filedType = filed.getType().getName();
            if (filedType != null && filedType.length() <= 8) {
            	 if ("boolean".equals(filedType)) {
   	    		  codeBuidler.append("\n boolean value"+(i*2)+" = info1.is"+getFiledStr+"();");
   		    	  codeBuidler.append("\n boolean value"+(i*2+1)+" = info2.is"+getFiledStr+"();");
   		    	  codeBuidler.append("\n if (value"+(i*2)+" == value"+(i*2+1)+") result = 0;else if (value"+(i*2)+") result = 1;else if (value"+(i*2+1)+") result = -1;");
   	    	  } else {
		   	    	  codeBuidler.append("\n"+filedType +" value"+(i*2)+" = info1.get"+getFiledStr+"();");
		   	    	  codeBuidler.append("\n"+filedType +" value"+(i*2+1)+" = info2.get"+getFiledStr+"();");
		   	    	  codeBuidler.append("\n if (value"+(i*2)+" > value"+(i*2+1)+") result = 1;else if (value"+(i*2)+" < value"+(i*2+1)+") result = -1;");
   	    	  }
            } else {
                codeBuidler.append("\nComparable value" + (i * 2) + " = info1.get" + getFiledStr + "();");
                codeBuidler.append("\nComparable value" + (i * 2 + 1) + " = info2.get" + getFiledStr + "();");
                codeBuidler.append("\nif (null == value" + (i * 2) + " && value" + (i * 2 + 1) + " == null) result = 0;else if (null == value" + (i * 2 + 1) + ") return -1; else if (null == value" + (i * 2) + ") return 1;");
                codeBuidler.append("\nelse if (value" + (i * 2) + " instanceof java.lang.String) {java.util.Comparator pinyinComparator = new PinyinComparator();result = pinyinComparator.compare((String)value" + (i * 2) + ", (String)value" + (i * 2 + 1) + ");}");
                codeBuidler.append("\nelse {result = value" + (i * 2) + ".compareTo(value" + (i * 2 + 1) + ");}");
            }
            codeBuidler.append("\nif (result !=0) {");
            codeBuidler.append("\nif (" + orderField.isDesc() + ") result = 0 - result;");
            codeBuidler.append("\nreturn result;");
            codeBuidler.append("}");
        }

        codeBuidler.append("return result;}");
        codeBuidler.append("}");
        return codeBuidler.toString();
    }

    /**
     * 将src 进行classloader
     *
     * @param name   className
     * @param source 代码
     * @return
     * @throws Throwable
     */
    public static Class<?> doCompile(String name, String source) throws Throwable {
        int i = name.lastIndexOf('.');
        String className = i < 0 ? name : name.substring(i + 1);
        ClassPool pool = new ClassPool(true);
        pool.appendClassPath(new LoaderClassPath(OrderUtils.class.getClassLoader()));
        Matcher matcher = IMPORT_PATTERN.matcher(source);
        List<String> importPackages = new ArrayList<String>();
        Map<String, String> fullNames = new HashMap<String, String>();
        while (matcher.find()) {
            String pkg = matcher.group(1);
            if (pkg.endsWith(".*")) {
                String pkgName = pkg.substring(0, pkg.length() - 2);
                pool.importPackage(pkgName);
                importPackages.add(pkgName);
            } else {
                int pi = pkg.lastIndexOf('.');
                if (pi > 0) {
                    String pkgName = pkg.substring(0, pi);
                    pool.importPackage(pkgName);
                    importPackages.add(pkgName);
                    fullNames.put(pkg.substring(pi + 1), pkg);
                }
            }
        }
        CtClass cls = pool.makeClass(name);
        matcher = IMPLEMENTS_PATTERN.matcher(source);
        if (matcher.find()) {
            String[] ifaces = matcher.group(1).trim().split("\\,");
            for (String iface : ifaces) {
                iface = iface.trim();
                String ifaceClass;
                ifaceClass = iface;
                cls.addInterface(pool.get(ifaceClass));
            }
        }
        String body = source.substring(source.indexOf("{") + 1, source.length() - 1);
        String[] methods = METHODS_PATTERN.split(body);
        for (String method : methods) {
            method = method.trim();
            if (method.length() > 0) {
                if (method.startsWith(className)) {
                    cls.addConstructor(CtNewConstructor.make("public " + method, cls));
                } else if (FIELD_PATTERN.matcher(method).matches()) {
                    cls.addField(CtField.make("private " + method, cls));
                } else {
                    cls.addMethod(CtNewMethod.make("public " + method, cls));
                }
            }
        }
        return cls.toClass(OrderUtils.class.getClassLoader(), null);
    }

    /**
     * 得到生成Comparator的类名
     *
     * @param t      类
     * @param orders 排序字段
     * @return 类名
     */
    protected static String getNewClassName(Class t, OrderField... orders) {
        StringBuilder sb = new StringBuilder();
        sb.append(t.getSimpleName()).append("$");
        for (OrderField filed : orders) {
            //降序为1，升序为0
            sb.append(filed.getFiled()).append(filed.isDesc() ? 1 : 0);
        }
        return sb.toString();
    }

    protected static Comparator getComparator(String comparatorClassName) {
        return comparators.get(comparatorClassName);
    }

    protected static Comparator addComparator(String comparatorClassName, Comparator comparator) {
        return comparators.put(comparatorClassName, comparator);
    }


}